package com.txts.base.module.support.file.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import com.txts.base.common.domain.ResponseDTO;
import com.txts.base.common.util.SmartStringUtil;
import com.txts.base.config.FileConfig;
import com.txts.base.constant.enums.FileSaveModeEnum;
import com.txts.base.module.support.file.domain.vo.FileDownloadVO;
import com.txts.base.module.support.file.domain.vo.FileMetadataVO;
import com.txts.base.module.support.file.domain.vo.FileUploadVO;
import com.txts.base.module.support.file.service.IFileStorageService;
import io.minio.*;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.Date;

/**
 * @author baoyr
 * @version 1.0
 * @description: minio实现类
 * @date 2025/7/22 10:07
 */
public class MinioStorageServiceImpl implements IFileStorageService {

    @Resource
    private MinioClient minioClient;

    @Resource
    private FileConfig fileConfig;


    /**
     * 获取时间路径
     *
     * @return 时间路径
     */
    private String getTimePath() {
        return DateUtil.format(new Date(), "yyyy-MM-dd") + "/";
    }


    @Override
    public ResponseDTO<FileUploadVO> upload(MultipartFile file, String path) {
        String originalFileName = file.getOriginalFilename();
        if (SmartStringUtil.isEmpty(originalFileName)) {
            return ResponseDTO.userErrorParam("上传文件名为空");
        }
        String fileType = FilenameUtils.getExtension(originalFileName);
        String fileMd5 = SecureUtil.md5(originalFileName) + "-";
        if (ObjectUtils.isEmpty(path)) {
            path = getTimePath() + fileMd5 + originalFileName;
        } else {
            path = path + fileMd5 + originalFileName;
        }
        try {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(fileConfig.getMinioBucketName())
                            .object(path)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build());
            return ResponseDTO.ok(FileUploadVO.builder()
                    .fileName(file.getOriginalFilename())
                    .fileUrl(getPublicUrl(path))
                    .fileKey(path)
                    .fileMode(FileSaveModeEnum.MINIO.getValue())
                    .fileSize(file.getSize())
                    .fileType(fileType)
                    .build());
        } catch (Exception e) {
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }


    /**
     * 获取文件公开访问URL
     *
     * @param filename 文件名
     * @return 文件公开访问URL
     */
    private String getPublicUrl(String filename) {
        return fileConfig.getMinioEndpoint() + "/" + fileConfig.getMinioBucketName() + "/" + filename;
    }

    @Override
    public ResponseDTO<String> getFileUrl(String fileKey) {
        return ResponseDTO.ok(getPublicUrl(fileKey));
    }

    @Override
    public ResponseDTO<FileDownloadVO> download(String key) {
        try {
            StatObjectResponse stat = minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(fileConfig.getMinioBucketName())
                            .object(key)
                            .build()
            );
            InputStream inputStream = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(fileConfig.getMinioBucketName())
                            .object(key)
                            .build());
            FileDownloadVO fileDownloadVO = FileDownloadVO.builder()
                    .data(inputStream.readAllBytes())
                    .metadata(FileMetadataVO.builder()
                            .fileFormat(FilenameUtils.getExtension(key))
                            .fileName(FilenameUtils.getName(key))
                            .fileSize(stat.size())
                            .build())
                    .build();
            return ResponseDTO.ok(fileDownloadVO);
        } catch (Exception e) {
            throw new RuntimeException("文件获取失败: " + e.getMessage());
        }
    }

    @Override
    public ResponseDTO<String> delete(String fileKey) {
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(fileConfig.getMinioBucketName())
                            .object(fileKey)
                            .build());
            return ResponseDTO.ok();
        } catch (Exception e) {
            throw new RuntimeException("文件删除失败: " + e.getMessage());
        }
    }
}
